<?php

/*
 * Auth: PZ
 * Date: 2010-10-23
 * Desc: Provides an easy interface to commonly used string encoding.
 *

CodecHelper::setUtf8ToGbkDecoder();
print CodecHelper::E("hello你好");
CodecHelper::setGbkToUtf8Decoder();
print CodecHelper::E("hello你好");

 */


/*
 *  CodecHelper::getInstance() :
 *      Get globally unique CodecHelper instance.
 *
 *  CodecHelper::E(...) :
 *      String encode.
 *
 *  CodecHelper::D(...) :
 *      String decode.
 *
 *  CodecHelper::EA(...) :
 *      Recursively from one coding to another coding. If the array 
 *      contains non-string, then non-string will be ignored.
 *
 *  CodecHelper::DA(...) :
 *      Decode array, lbid.
 *
 *  CodecHelper::setUtf8ToGbkDecoder(),
 *  CodecHelper::setGbkToUtf8Decoder(),
 *  CodecHelper::setNoneDecoder() :
 *      A quick way to set three different Decoder.
 *
 * */
class CodecHelper {

    private static $__instance = NULL;    

    private function CodecHelper () {
        $this->decoder = new U2GDecoder();
    }
    public static function getInstance () {
        if (self::$__instance == NULL) {
            self::$__instance = new CodecHelper();
        }
        return self::$__instance;
    }

    public function encode ($str) {
        return $this->decoder->encode($str);
    }
    public function decode ($str) {
        return $this->decoder->decode($str);
    }
    public function encodeArray ($arr) {
        return $this->decoder->encodeArray($arr);
    }
    public function decodeArray ($arr) {
        return $this->decoder->decodeArray($arr);
    }
    public function setDecoder ($decoder) {
        //TODO: check decoder is instance Decoder
        $this->decoder = $decoder;
    }

    public static function setUtf8ToGbkDecoder () {
        $instance = self::getInstance();
        $instance->setDecoder(new U2GDecoder());
    }
    public static function setGbkToUtf8Decoder () {
        $instance = self::getInstance();
        $instance->setDecoder(new G2UDecoder());
    }
    public static function setNoneDecoder() {
        $instance = self::getInstance();
        $instance->setDecoder(new NoneDecoder());
    }


    public static function E ($str) {
        $instance = self::getInstance();
        return $instance->encode($str);
    }

    public static function D ($str) {
        $instance = self::getInstance();
        return $instance->decode($str);
    }

    public static function EA ($str) {
        $instance = self::getInstance();
        return $instance->encodeArray($str);
    }
    public static function DA ($str) {
        $instance = self::getInstance();
        return $instance->decodeArray($str);
    }


}

/*
 * Decoder abstract description and some static transfer 
 * function.
 *
 * static functions :
 *  Decoder::gbkToUtf8(...) : 
 *  Decoder::utf8ToGbk(...) :
 *  Decoder::arrayGbkToUtf8(...) :
 *  Decoder::arrayUtf8ToGbk(...) :
 *
 * abstract functions :
 *  encode (...);
 *  decode (...);
 *  encodeArray (...);
 *  decodeArray (...);
 *
 * */
abstract class Decoder {

    public abstract function encode ($str);
    public abstract function decode ($str);

    public abstract function encodeArray ($arr);
    public abstract function decodeArray ($arr);

    public static function utf8ToGbk ($str) {
        return mb_convert_encoding($str, 'GBK', 'UTF-8'); 
    }

    public static function gbkToUtf8 ($str) {
        return mb_convert_encoding($str, 'UTF-8', 'GBK');
    }

    public static function arrayGbkToUtf8($arr) {
        if (!is_array($arr)) {
            return $arr;
        }
        foreach ($arr as $key=>$value) {
            if (is_string($key)) {
                $key = self::gbkToUtf8($key);
            } else if (is_array($key)) {
                $key = self::arrayGbkToUtf8($key);
            }
            if (is_string($value)) {
                $value = self::gbkToUtf8($value);
            } else if (is_array($value)) {
                $value = self::arrayGbkToUtf8($value);
            }
            $arr[$key] = $value;
        }
        return $arr;
    }
    public static function arrayUtf8ToGbk($arr) {
        if (!is_array($arr)) {
            return $arr;
        }
        foreach ($arr as $key=>$value) {
            if (is_string($key)) {
                $key = self::utf8ToGbk($key);
            } else if (is_array($key)) {
                $key = self::arrayUtf8ToGbk($key);
            }
            if (is_string($value)) {
                $value = self::utf8ToGbk($value);
            } else if (is_array($value)) {
                $value = self::arrayUtf8ToGbk($value);
            }
            $arr[$key] = $value;
        }
        return $arr;
    }

}

/*
 * UTF8 -> GBK
 * */
class U2GDecoder extends Decoder {

    public function encode ($str) {
        return Decoder::utf8ToGbk($str);
    }
    public function decode ($str) {
        return Decoder::gbkToUtf8($str);
    }
    
    public function encodeArray ($arr) {
        return Decoder::arrayUtf8ToGbk($arr);
    }
    public function decodeArray ($arr) {
        return Decoder::arrayGbkToUtf8($arr);
    }

}

/*
 * GBK -> UTF-8
 * */
class G2UDecoder extends Decoder {

    public function encode ($str) {
        return Decoder::gbkToUtf8($str);
    }
    public function decode ($str) {
        return Decoder::utf8ToGbk($str);
    }
    public function encodeArray ($arr) {
        return Decoder::arrayGbkToUtf8($arr);
    }
    public function decodeArray ($arr) {
        return Decoder::arrayUtf8ToGbk($arr);
    }
    
}

/*
 * No conversion.
 * */
class NoneDecoder extends Decoder {

    public function encode ($str) {
        return $str;
    }
    public function decode ($str) {
        return $str;
    }
    public function encodeArray ($arr) {
        return $arr;
    }
    public function decodeArray ($arr) {
        return $arr;
    }

}







